package engine.gameObject.collider;

import java.util.ArrayList;

import engine.gameObject.GameObject;

public class SphereCollider extends Collider {

	private SphereCollider origin;
	
	private BoundingSphere root;
	
	public SphereCollider() {
		root = new BoundingSphere(0, new float[]{0, 0, 0});
	}
	
	private SphereCollider(BoundingSphere root) {
		this.root = root;
	}
	
	@Override
	public boolean collides(GameObject g1, GameObject g2) {
		SphereCollider collider1 = (SphereCollider)g1.getCollider();
		SphereCollider collider2 = (SphereCollider)g2.getCollider();
		
		BoundingSphere sphere1 = collider1.getRoot();
		BoundingSphere sphere2 = collider2.getRoot();
		
		sphere1.setRadius(g1.getBoundingRadius());
		sphere2.setRadius(g2.getBoundingRadius());
		
//		System.out.println("start");
		
		return check(g1, sphere1, g2, sphere2, 0, 0);
	}
	
	/**
	 *  
	 * @param g1
	 * @param g2
	 * @return
	 */
	private boolean check(GameObject g1, BoundingSphere sphere1, GameObject g2, BoundingSphere sphere2, int level1, int level2) {
		sphere1.updatePosition(g1);
		sphere2.updatePosition(g2);
		
		if(sphereInSphere(g1, sphere1, g2, sphere2)) {
			if(sphere1.getChildren().size() != 0) {
				//if the subcheck of s against the children of sphere1 return true, this function should return true
//				System.out.println("can switch");
				for(BoundingSphere s: sphere1.getChildren()) {
					if(check(g2, sphere2, g1, s, level2, level1 + 1)) {
						return true;
					}
				}
				
				//if the if part has not been entered, it is checked against the next child of sphere2. Thus, this is depth first collision detection
			} else {
				//if s has more children, check against them
				if(sphere2.getChildren().size() != 0) {
					//if the subcheck of sphere1 against the children of s returns true, this function should return true
//					System.out.println("cannot switch");
					
					for(BoundingSphere s: sphere2.getChildren()) {
						if(check(g1, sphere1, g2, s, level1, level2 + 1)) {
							return true;
						}
					}
					
					//if the if part has not been entered, it is checked against the next child of sphere2. Thus, this is depth first collision detection
				} else {
					//this else leaf is entered if s and sphere1 have no children. then this is the lowest level and the two objects are colliding. 
//					System.out.println("found collision of: " + g1.getId() + " " + g2.getId() + " (level: " + level1 + "  " + level2 + ")");
					g1.collidesAbs(g2, null);
					g2.collidesAbs(g1, null);
					return true;
				}
			}
		}
		
//		System.out.println("none");
		return false;
	}
	
	private boolean sphereInSphere(GameObject g1, BoundingSphere sphere1, GameObject g2, BoundingSphere sphere2) {
		return sphereInSphere(sphere1.getPosition(), sphere1.getRadius(), sphere2.getPosition(), sphere2.getRadius());
		
//		return sphereInSphere(g1.getPosX() + sphere1.getPosition()[0], g1.getPosY() + sphere1.getPosition()[1], g1.getPosZ() + sphere1.getPosition()[2], sphere1.getRadius(), 
//				g2.getPosX() + sphere2.getPosition()[0], g2.getPosY() + sphere2.getPosition()[1], g2.getPosZ() + sphere2.getPosition()[2], sphere2.getRadius());
	}
	
	public void addSphere(BoundingSphere boundingSphere) {
		root.addSphere(boundingSphere);
	}

	public ArrayList<BoundingSphere> getChildren() {
		return root.getChildren();
	}
	
	private BoundingSphere getRoot() {
		return root;
	}
	
	public void setOrigin(SphereCollider origin) {
		this.origin = origin;
	}
	
	public SphereCollider getOrigin() {
		return origin;
	}
	
	@Override
	public Collider copy() {
		return new SphereCollider(getRoot().copy());
	}
	
	@Override
	public void reset() {
		root.reset();
	}
}
